class Person { // 类体，不是对象，不能按照对象来书写
  // 类的构造函数
  // new Person 的时候会自动调用
  // 构造函数的作用用于对实例进行初始化操作
  constructor (name, age) {
    console.log('Person 的构造函数被调用了')
    this.name = name
    this.age = age
  }

  // 实例方法直接写到类的内部
  // 语法注意：
  //  方法名称 () { 方法体 }
  //  在实例方法内部的 this 是实例自己
  //  类的成员与成员之间不能有逗号
  sayHello () {
    console.log(`大家好，我叫${this.name}，我今年${this.age}岁了`)
  }

  haha () {
    console.log('哈哈哈')
  }

  // 除了实例方法，还可以有静态方法
  // 静态成员只能被类本身来访问
  static hehe () {
    console.log('呵呵')
  }
}

// 继承实例成员+静态成员都会继承过来
// 静态成员会继承给子类本身
class Student extends Person {
  constructor (name, age, stuId) {
    // 在子类的构造函数中的 super 指向的是父类构造函数
    // 这句代码相当于借用父类构造函数来初始化子类成员
    // 这里调用 super ，内部的 this 指向的是子类实例
    // 注意：有继承的类必须在自己的构造函数内部显示调用 super 函数
    //      如果子类没有写构造函数，则可以不调用
    super(name, age)
    this.stuId = stuId
  }

  // 一般情况下都是在构造函数内部通过 this.xxx = xxx 初始化实例成员
  // 在新版的 ES6 中，还提供了一种新的方式，可以在构造函数外部对实例成员初始化
  // Node 还不支持这种语法
  // 可以去在线的 babel 编译测试
  //    babeljs.io
  // 但是我们 babel 编译器已经支持了
  foo = 'bar'

  study () {
    console.log(`${this.name} 要学习`)
  }
}

const s1 = new Student('李四', 18, 123456)
Student.hehe()
s1.study()

// s1.sayHello()

// var p1 = new Person('张三', 18)
// p1.sayHello()
// p1.haha()
// Person.hehe()
// p1.hehe()


// function Person (name, age) {
//   this.name = name
//   this.age = age
// }

// Person.prototype.sayHello = function () {
//   console.log(`大家好，我叫${this.name}，我今年${this.age}岁了`)
// }
